package org.scirp.ijmis.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;

public class HibernateLazySpringResolver implements InitializingBean {

	private static final Log log = LogFactory.getLog(HibernateLazySpringResolver.class);

	private SessionFactory sessionFactory;

	private boolean sigleSession = true;

	private boolean deferMark = false;

	protected Session session;

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public boolean isSigleSession() {
		return sigleSession;
	}

	public void setSigleSession(boolean sigleSession) {
		this.sigleSession = sigleSession;
	}

	public boolean isDeferMark() {
		return deferMark;
	}

	public void setDeferMark(boolean deferMark) {
		this.deferMark = deferMark;
	}

	public void afterPropertiesSet() throws Exception {

		if (sessionFactory == null) {
			log.error("sessionFactory was needed!", new RuntimeException());
		}
	}

	public void openSession() {

		if (isSigleSession()) {

			if (TransactionSynchronizationManager.hasResource(sessionFactory)) {

				setDeferMark(true);
			}

			else {

				log.debug("Opening single Hibernate Session in HibernateLazySpringResolver");

				session = getSession();

				TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
			}
		}

		else {

			if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {

				setDeferMark(true);
			} else {
				SessionFactoryUtils.initDeferredClose(sessionFactory);
			}
		}
	}

	public void releaseSession() {

		if (!deferMark) {

			if (isSigleSession()) {
				TransactionSynchronizationManager.unbindResource(sessionFactory);
				log.debug("Closing single Hibernate Session in HibernateLazySpringResolver");
				try {
					closeSession(session, sessionFactory);
				} catch (RuntimeException ex) {
					log.error("Unexpected Exception ocurred on closing Hibernate session!", ex);
				}
			}

			else {
				SessionFactoryUtils.processDeferredClose(sessionFactory);
			}
		}
	}

	private void closeSession(Session session, SessionFactory sessionFactory) {
		if (session != null && session.isOpen()) {

			session.flush();
			SessionFactoryUtils.releaseSession(session, sessionFactory);
		}
	}

	@SuppressWarnings("deprecation")
	protected Session getSession() {
		Session session = SessionFactoryUtils.getSession(sessionFactory, true);
		session.setFlushMode(FlushMode.NEVER);
		return session;
	}

}
